package pl.enigmatic.parser.metadata;

import java.util.HashMap;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import pl.enigmatic.util.Enums;
import pl.enigmatic.parser.xml.Parser;


/**
 * The metadata nodes information identifiers. The order of items is important for parsing purposes.
 * @author reggie_7
 * 
 */
public enum Metadata {
	NAME(true), //
	REF(true), //
	INCLUDE(true), //
	NULL(true), //
	CLASS(true), //
	KEY(true), //
	VALUE(true), //
	ITEM(false), //
	CONTENT(true), //
	SOURCE(true), //
	PATH(true), //
	PARAM(true), //
	CONSTRUCTOR(true);

	public static final String XMLNS = Parser.XMLNS("metadata");

	private final boolean removable;

	private Metadata(boolean removable) {
		this.removable = removable;
	}

	@Override
	public String toString() {
		return Enums.convertNameToJavaStyle(this);
	}

	public static Metadata from(final Node node) {
		return Enum.valueOf(Metadata.class, Enums.convertNameFromJavaStyle(node.getLocalName()));
	}

	public static final boolean has(final Node node, final Metadata key) {
		return node instanceof Element && ((Element) node).hasAttributeNS(XMLNS, key.toString());
	}

	/** does the <code>node</code> have me as an attribute? */
	public final boolean isPresent(final Node node) {
		return has(node, this);
	}

	public static final String getString(final Node node, final Metadata key) {
		if (has(node, key)) { return ((Element) node).getAttributeNS(XMLNS, key.toString()); }
		return null;
	}

	public final String getString(final Node node) {
		return getString(node, this);
	}

	/**
	 * Checks whether the passed <code>node</code> represents metadata information for this specific constant value.
	 * @param node the node to check
	 * @return <code>true</code>, if the <code>node</code> represents metadata information and the metadata is represented by <code>this</code>
	 *         constant, otherwise - <code>false</code>
	 */
	public final boolean equals(final Node node) {
		return is(node) && toString().equals(node.getLocalName());
	}

	/**
	 * Checks whether the passed <code>node</code> represents metadata information.
	 * @param node the node to check
	 * @return <code>true</code>, if the <code>node</code> represents metadata information, otherwise - <code>false</code>
	 */
	public static final boolean is(final Node node) {
		return XMLNS.equals(node.getNamespaceURI());
	}

	public static HashMap<Metadata, String> get(final Element node) {
		final NamedNodeMap attr = node.getAttributes();
		final HashMap<Metadata, String> metadata = new HashMap<Metadata, String>();
		for (int i = 0; i < attr.getLength(); i++) {
			final Node item = attr.item(i);
			if (XMLNS.equals(item.getNamespaceURI())) {
				metadata.put(from(item), item.getNodeValue());
			}
		}
		return metadata;
	}

	public boolean isRemovable() {
		return removable;
	}
}